﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RiskCalc.Modelo
{
    public class CarteiraSimulacao : RiskCalc.Modelo.Carteira
    {
        public double[,] MatrizDecomposicaoCholesky;
        public double VarHistorico;
        public double VarMonteCarlo;
        public List<Double> VetPerdasOuGanhosHistorico;
        public List<Double> VetPerdasOuGanhosMonteCarlo;

        #region Singleton

        private static CarteiraSimulacao instancia;

        public static new CarteiraSimulacao getInstance()
        {
            if (instancia == null)
            {
                instancia = new CarteiraSimulacao();
            }
            return instancia;
        }

        protected CarteiraSimulacao() : base()
        {
            this.VetPerdasOuGanhosHistorico = new List<double>();
            this.VetPerdasOuGanhosMonteCarlo = new List<double>();
        }

        #endregion

        public void calcularMatrizDecomposicaoCholesky()
        {
            MatrizDecomposicaoCholesky = new double[vetAcao.Count, vetAcao.Count];

            // copia a matriz de covariancia para a matriz de cholesky
            for (int i = 0; i < vetAcao.Count; i++)
            {
                for (int j = 0; j < vetAcao.Count; j++)
                {
                    MatrizDecomposicaoCholesky[i, j] = this.matrizCovariancia[i,j];
                }
            }

            // Modifica a matriz de cholesky
            Calculos.decomposicaoCholesky(ref MatrizDecomposicaoCholesky, this.vetAcao.Count, true);
        }

        public void calcularVarHistorico()
        {
            foreach (AcaoSimulacao acao in vetAcao)
            {
                acao.calcularPerdasOuGanhos();

                acao.calcularVarHistorico(confianca);
            }

            this.calcularVetPerdasOuGanhosHistorico();

            this.VarHistorico = Calculos.percentil(this.VetPerdasOuGanhosHistorico, confianca);
        }

        public void calcularVarMonteCarlo(int numAmostras)
        {
            Random random = new Random();
            double[,] matrizAux = new double[numAmostras, vetAcao.Count];

            // MC1
            for (int i = 0; i < numAmostras; i++)
            {
                for (int j = 0; j < vetAcao.Count; j++)
                {
                    matrizAux[i, j] = Calculos.inversaDistNormal(random.NextDouble());
                }
            }

            this.calcularMatrizDecomposicaoCholesky();

            // MC2
            Calculos.multiplicarMatrizes(numAmostras, vetAcao.Count, vetAcao.Count, matrizAux,
                        Calculos.transpor(vetAcao.Count, vetAcao.Count, MatrizDecomposicaoCholesky));
            
            // MC3, MC4, MC5
            for (int i = 0; i < numAmostras; i++)
            {
                for (int j = 0; j < vetAcao.Count; j++)
                {
                    if (j == 0)
                    {
                        VetPerdasOuGanhosMonteCarlo.Add(Calculos.perdaOuGanho(vetAcao[j].Posicao, matrizAux[i, j]));
                    }
                    else
                    {
                        VetPerdasOuGanhosMonteCarlo[i] += Calculos.perdaOuGanho(vetAcao[j].Posicao, matrizAux[i, j]);
                    }
                }
            }

            // MC5
            this.VarMonteCarlo = Calculos.percentil(this.VetPerdasOuGanhosMonteCarlo, confianca);
        }

        public void calcularVetPerdasOuGanhosHistorico()
        {
            for(int i = 0; i < vetAcao.Count ; i++)
            {
                for(int j = 0; j < vetAcao[i].VetDados.Count - 1 ; j++)
                {
                    if (i == 0)
                    {
                        VetPerdasOuGanhosHistorico.Add(((DadoSimulacao)vetAcao[i].VetDados[j]).PerdaOuGanhoHistorico);
                    }
                    else
                    {
                        VetPerdasOuGanhosHistorico[j] += ((DadoSimulacao)vetAcao[i].VetDados[j]).PerdaOuGanhoHistorico;
                    }
                }
            }
        }
    }
}
